package com.longyb.mylive.server.jt1078;

import cn.hutool.core.math.BitStatusUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.longyb.mylive.server.util.BCDUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class ReadJT1078Bin {
  public static List<JT1078Msg> readFile() {
    try {
      URL file = ReadJT1078Bin.class.getResource("/14525285141.raw");
      File f = new File(file.getFile());
      byte[] buf = new byte[(int) f.length()];
      FileInputStream reader = new FileInputStream(f);
      reader.read(buf);
      reader.close();
      ByteBuf byteBuf = Unpooled.wrappedBuffer(buf);
//      ByteBuf cloneBuf = byteBuf.slice(0, byteBuf.readableBytes());
      List<JT1078Msg> msgList = new ArrayList<>();
      int n = 0;
      while (byteBuf.readableBytes() > 30) {


        JT1078Msg msg = new JT1078Msg();
        byte[] head = new byte[4];//head 4
        byteBuf.readBytes(head);
        msg.setHEAD(head);
        int exFlag = byteBuf.readByte();
        int v = exFlag >> 6 & 0x03;
        int p = exFlag >> 5 & 0x01;
        int x = exFlag >> 4 & 0x01;
        int cc = exFlag & 0x0F;
        msg.setExFlag(exFlag);//exflag 1byte;
        msg.setExV(v);
        msg.setExP(p);
        msg.setExX(x);
        ;
        msg.setExCC(cc);

        byte fmtFlag = byteBuf.readByte();
        int m = fmtFlag >> 7 & 0x01;
        int pt = fmtFlag & 0x7f;
        msg.setFmtFlag(fmtFlag);//fmtflag 1byte;
        msg.setFmtPT(pt);
        msg.setFmtM(m);

        msg.setSeq(byteBuf.readShort());//seq 2byte

        byte[] simBuf = new byte[6];
        byteBuf.readBytes(simBuf); //sim 6byte
        String simBcd = BCDUtil.bcdToDecimalString(simBuf);
        msg.setSim(simBcd);

        msg.setChannel(byteBuf.readByte()); /// 1byte 通道

        byte dataFlag = byteBuf.readByte(); //1byte
        int data1 = dataFlag >> 4 & 0xf; //分包
        int data2 = dataFlag & 0xf;
        //                log.info("datatype:{},split:{}",Integer.toBinaryString(data1),Integer.toBinaryString(data2));
        msg.setDataFlag(dataFlag); // 4bit 0000=I帧，0001=P帧， 0010=P帧， 0011=音频
        msg.setDataType(data1);
        msg.setDataSplit(data2);


        msg.setTimestamp(byteBuf.readLong()); // 8byte
        msg.setLastIFrameMs(byteBuf.readShort()); //2byte
        msg.setLastFrameMs(byteBuf.readShort());//2byte
        int rtpLen = byteBuf.readUnsignedShort();//2byte
        msg.setRtpLen(rtpLen);
        if(byteBuf.readableBytes()>=rtpLen){
          ByteBuf rtpBuf = byteBuf.readBytes(rtpLen);
          msg.setRtpData(rtpBuf);
        }

        //addleng
        msgList.add(msg);

        // print info
        String jtMedia =JT1078Msg.mediaType.get(msg.getFmtPT())+"("+msg.getFmtPT()+")";
        String frameType = JT1078Msg.frameType.get(msg.getDataType())+"("+msg.getDataType()+")";
        String packType = JT1078Msg.packType.get(msg.getDataSplit())+"("+msg.getDataSplit()+")";;


        log.info("第{}个包，媒体类型：{},帧类型:{}，分包参数：{}", n++, jtMedia, frameType, packType);

      }

      return msgList;


    } catch (Exception e) {
      e.printStackTrace();
    }

    return null;
  }

  private static final Set<Integer> typeSet = new HashSet<>();

  public static RTP decodeRTP(ByteBuf buf) {
    //        https://zhuanlan.zhihu.com/p/569915293
    RTP rtp = new RTP();
    byte f1 = buf.readByte();//1byte
    rtp.setFlag(Integer.valueOf(f1));
    rtp.setFV((f1 >> 6) & 0x03);
    rtp.setFP((f1 >> 5) & 0x01);
    rtp.setFX((f1 >> 4) & 0x01);
    rtp.setFCC(f1 & 0xF);

    byte dataFlag = buf.readByte();//1byte
    rtp.setDM(Integer.valueOf(dataFlag));
    rtp.setDM((dataFlag >> 7) & 0x01);
    rtp.setDPT(dataFlag & 0x7F);
    rtp.setSeq(buf.readUnsignedShort());//2byte
    rtp.setTimestamp(buf.readInt());//4byte
    rtp.setSsrc(buf.readInt());//4byte 一定有

    String hexFlag = Integer.toBinaryString(rtp.getFlag());
    hexFlag = StrUtil.padPre(hexFlag, 8, "0");
    log.info("BIN:{},X:{}，CC:{}", hexFlag, rtp.getFX(), rtp.getFCC());
    if (rtp.getFCC() > 0) { //有几个读几个
      //            buf.readBytes(rtp.getFCC()*4);//丢弃
    }
    if (rtp.getFX() > 0) { //最多15个
      byte[] profile = new byte[2];
      buf.readBytes(profile);
      log.info("扩展头：{}", HexUtil.encodeHexStr(profile));

    }


    byte phead = buf.readByte();
    rtp.setPFlag(Integer.valueOf(phead));
    rtp.setPF((phead >> 7) & 0x01);
    rtp.setPNRI((phead >> 5) & 0x03);
    rtp.setPType(phead & 0x1f);  //包类型


    return rtp;
  }

  @SneakyThrows
  public static void send2rtmp() throws IOException {
    List<String> cmd = new ArrayList<>();
    cmd.add("E:\\live\\ffmpeg-4.3.2\\bin\\ffmpeg.exe");
    //        cmd.add(" -protocol_whitelist \"rtp,file,udp\" -i pipe:0 -c copy -f flv rtmp://127.0.0.1/live/demo");
    cmd.add("ffmpeg -re -i pipe:0 -vcodec copy -f flv rtmp://127.0.0.1/live/demo ");


    Process process = new ProcessBuilder().command(cmd).directory(new File("./")).start();
    ExecutorService threadPool = Executors.newCachedThreadPool();
    BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
    threadPool.submit(new Runnable() {
      @SneakyThrows
      @Override
      public void run() {


        while (true) {
          String line = stdIn.readLine();
          if (null != line) {
            log.info("error:{}", line);
          } else {
            Thread.sleep(200);
          }
        }
      }
    });
    BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    threadPool.submit(new Runnable() {
      @SneakyThrows
      @Override
      public void run() {
        // 读取进程标准输出


        while (true) {
          String line = stdErr.readLine();
          if (null != line) {
            log.info("error:{}", line);
          } else {
            Thread.sleep(200);
          }
        }
      }
    });


    OutputStream out = process.getOutputStream();
    List<JT1078Msg> list = readFile();

    for (int i = 0; i < list.size(); i++) {
      JT1078Msg msg = list.get(i);
      log.info("size:{}->{} delay:{}", list.size(), i, msg.getLastFrameMs());
      log.info("再次读取:{}", msg.getSeq());

      int delay = msg.getLastFrameMs();
      Thread.sleep(delay);
      byte[] data = new byte[msg.getRtpLen()];
      msg.getRtpData().readBytes(data);

      //            out.write(data);
    }
    threadPool.shutdown();
    out.close();
    stdErr.close();
    stdIn.close();


  }

  public static void main(String[] args) throws IOException {
    readFile();

    //        send2rtmp();
  }
}
